#include "TinyThreadPool.h"

void tinyUtil::TinyThreadPool::stop() {
    {
        std::unique_lock<std::mutex> lock { mutex_ };
        running_ = false;
        notEmpty_.notify_all();
    }

    for (auto& thread : threads_) {
        thread->join();
    }
}

void tinyUtil::TinyThreadPool::run(tinyUtil::TinyThreadPool::Runnable task) {
    if (threads_.empty()) {
        task();
    } else {
        std::unique_lock<std::mutex> lock { mutex_ };
        if (!running_) return;
        workQueue_.push(std::move(task));
        notEmpty_.notify_all();
    }
}

tinyUtil::TinyThreadPool::Runnable tinyUtil::TinyThreadPool::take() {
    std::unique_lock<std::mutex> lock { mutex_ };
    while (workQueue_.empty() && running_) {
        notEmpty_.wait(lock);
    }
    Runnable r;
    // because stop(): notify all blocking threads
    if (!workQueue_.empty()) {
        r = workQueue_.front();
        workQueue_.pop();
    }
    return r;
}

void tinyUtil::TinyThreadPool::start(unsigned numThreads) {
    threads_.reserve(numThreads);
    running_ = true;
    auto runInThread = [this]() {
        while (this->running_) {
            Runnable task { take() };
            if (task) {
                task();
            }
        }
    };
    for (auto i { 0u }, n { numThreads }; i < n; ++i) {
        threads_.emplace_back(new std::thread(runInThread));
    }
}

